<!--
 * @Description: ------------ fileDescription -----------
 * @Author: snows_l snows_l@163.com
 * @Date: 2024-08-31 12:42:12
 * @LastEditors: snows_l snows_l@163.com
 * @LastEditTime: 2025-01-10 09:53:14
 * @FilePath: \BLOG\src\components\common\CommentView.vue
-->
<!--
  * @Description: 评论展示组件
  *props:
  *  articleId: 文章id
  *  list: 评论列表
  *emits:
  *  submit: 评论提交
 -->
<template>
  <div class="comment-view-container" :class="{ 'm-comment-view-container': isMobi }">
    <div class="max-width-center">
      <p style="font-size: 16px; margin-bottom: 20px; line-height: 24px">
        声明：评论区均会
        <span style="color: red">“通过敏感词检测”</span>
        并且由站长
        <span style="color: red">“审核通过”</span>
        之后再进行展示。如有不当言论，请联系站长进行删除处理。
      </p>
      <div class="comment-view-content" :style="{ marginBottom: state.page.total <= state.page.size ? '30px' : '0px' }" v-if="state.list && state.list.length > 0">
        <div class="comment-item" v-for="item in state.list" :key="item.id">
          <div class="info-warp">
            <div class="avatar-warp">
              <img :src="getQQAvatar(item.qq)" />
            </div>
            <div class="info">
              <div class="nick-name">
                <span style="margin: 0 4px">{{ item.nickName }}</span>
                <div class="bozhu" v-if="item.qq === '37523953'">站长</div>
                <div
                  class="bozhu level"
                  :style="{ color: item.qq === '37523953' ? '#ff6600' : '#d3a833', border: item.qq === '37523953' ? '1px solid #ff6600' : '1px solid #d3a833' }"
                  style="margin-left: 5px; margin-right: 5px">
                  Lv{{ item.qq == '37523953' ? '10' : '2' }}
                </div>
              </div>
              <div class="time-add">
                <span>{{ getTime(item.time) }}</span>
                <span style="margin-left: 10px">归属地：{{ item.city }}</span>
              </div>
            </div>
          </div>
          <div class="msg-content-warp">
            <div class="content">
              {{ item.comment }}
            </div>
            <div class="operation-warp">
              <div class="like-warp">
                <IconLike :size="18" :animation="item.isGood" class="iconfont pointer" @click="handleGood(item)"></IconLike>
                <span class="like-value">{{ item.likeCount || 0 }}</span>
              </div>
              <div class="comment-warp pointer" @click="handleComment(item.id, item)">
                <img class="comment-icon" src="@/assets/images/icon/icon_comment.svg" alt="" />
                <span class="comment-value">{{ (item.children && item.children.length) || 0 }}</span>
              </div>
            </div>
          </div>
          <div class="sub-comment" v-if="item.children && item.children.length > 0">
            <div class="sub-padding">
              <div class="sub-comment-item pointer" v-for="subItem in item.children" :key="subItem.id">
                <div class="title">
                  <span>{{ subItem.nickName }}</span>
                  <div class="bozhu" v-if="subItem.qq === '37523953'">站长</div>
                  <span style="margin: 0 6px; color: var(--theme-light-color-4)">回复</span>
                  <span>{{ subItem.toNickName }}：</span>
                </div>
                <div class="msg-content-warp">
                  <div class="sub-content">{{ subItem.comment }}</div>
                  <div class="operation-warp">
                    <div class="like-warp">
                      <IconLike :size="18" :animation="subItem.isGood" class="iconfont pointer" @click="handleGood(subItem)"></IconLike>
                      <span class="like-value">{{ subItem.likeCount || 0 }}</span>
                    </div>
                    <div class="comment-warp pointer" @click="handleComment(item.id, subItem)">
                      <img class="comment-icon" src="@/assets/images/icon/icon_comment.svg" alt="" />
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div v-else class="no-comment">
        <Empty :text="'暂无评论数据，期待您的评论~'" :loadingText="'评论正在拼命加载中...'"></Empty>
      </div>

      <div class="botom-warp" style="display: flex; justify-content: center; align-items: center">
        <LoadingMore
          v-if="store.projectConfig.pageType == 'more'"
          :loading="state.loading"
          :hasMore="state.isMore"
          :length="state.list.length"
          @loadMore="handleLoadMore"></LoadingMore>
        <CustomPage v-else :page="state.page" @change="handlePageChange" :loading="state.loading" scorllTop="max-width-center"></CustomPage>
      </div>

      <div class="input-warp" ref="commentInputRef">
        <div class="ttt">
          <div class="input-title" v-if="articleId != state.form.pId && state.form.pId">
            回复：
            <span :style="{ color: 'var(--theme-color)' }">{{ state.form.toNickName }}</span>
            <div class="bozhu" v-if="state.form.toQQ === '37523953'">站长</div>
          </div>
          <div class="back-title back-me pointer" @click="clearTO">评论文章</div>
        </div>
        <CommentInput v-model="state.comment" @submit="handleSubmit"></CommentInput>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { addComment, addLike, getCommentList2 } from '@/api/comment';
import useResize from '@/hooks/useResize';
import { getQQAvatar, getTime, CustomMessage, tranListToTree } from '@/utils/common';
import { reactive, ref, nextTick, watch } from 'vue';
const { isMobi } = useResize();
import { useAppStore } from '@/store/app';

const store = useAppStore();

const props = defineProps({
  articleId: {
    type: Number,
    default: 0
  }
});

const emits = defineEmits(['submit']);

const commentInputRef = ref(null);

const state = reactive({
  loading: false,
  isMore: true,
  page: {
    page: 1,
    size: 5,
    total: 0
  },
  list: [],
  comment: {
    value: '',
    qq: '',
    nickName: '',
    avatarUrl: '',
    email: '',
    websiteUrl: '',
    isPrivacy: false,
    isEmailFeekback: true,
    submitLoading: false
  },
  form: {
    articleId: props.articleId,
    pId: 0,
    toId: 0,
    toNickName: ''
  }
});

// 获取评论列表
const handleGetCommentFn = scorllTopCallback => {
  state.loading = true;
  let params = {
    articleId: props.articleId,
    ...state.page
  };
  getCommentList2(params)
    .then(res => {
      if (res.code == 200) {
        if (store.projectConfig.pageType == 'more') {
          state.list = tranListToTree([...state.list, ...res.data], 'id', 'pId', 'children');
        } else {
          state.list = tranListToTree(res.data, 'id', 'pId', 'children');
        }
        state.page.total = res.total;
        if (state.list.length >= res.total) {
          state.isMore = false; // 已经没有更多数据了
        }
        scorllTopCallback && scorllTopCallback();
      }
    })
    .catch(() => {})
    .finally(() => {
      state.loading = false;
    });
};

// 加在更多
const handleLoadMore = () => {
  state.page.page++;
  handleGetCommentFn();
};

const handlePageChange = (page: number, size: number, scorllTopCallback: Function) => {
  state.page.page = page;
  state.page.size = size;
  handleGetCommentFn(scorllTopCallback);
};

// 点赞
const handleGood = row => {
  addLike({ id: row.id }).then(res => {
    row.isGood = true;
    if (res.code === 200) {
      row.likeCount = res.data;
      setTimeout(() => {
        row.isGood = false;
      }, 500);
    }
  });
};

// 滚动到底部留言并且然输入框聚焦
const handleScrollToBottom = () => {
  nextTick(() => {
    let top = 0;
    const layoutEle: Element = document.querySelector('#layout') as Element;
    const commentInputEle: Element = document.querySelector('.comment-value-inner') as Element;
    if (commentInputRef.value) {
      top = (commentInputRef.value as Element).offsetTop - 60;
      layoutEle.scrollTo({ top, behavior: 'smooth' });
    }
    if (commentInputEle) commentInputEle.focus();
  });
};

// 处理点击评论
const handleComment = (pid, row) => {
  state.form.pId = pid;
  state.form.toId = row.id;
  state.form.toQQ = row.qq;
  state.form.toNickName = row.nickName;
  handleScrollToBottom();
};

// 提交评论
const handleSubmit = () => {
  let params = {
    ...state.comment,
    comment: state.comment.value,
    isPrivacy: state.comment.isPrivacy ? 1 : 0,
    isEmailFeekback: state.comment.isEmailFeekback ? 1 : 0,
    ...state.form,
    type: 1
  };
  addComment(params).then(res => {
    if (res.code === 200) {
      state.form.pId = 0;
      state.form.toNickName = '';

      state.comment.value = '';
      state.comment.qq = '';
      state.comment.nickName = '';
      state.comment.avatarUrl = '';
      state.comment.email = '';
      state.comment.websiteUrl = '';
      state.comment.isPrivacy = false;
      state.comment.isEmailFeekback = true;
      state.comment.submitLoading = false;
      CustomMessage({ msg: '评论成功, 站长会在24小时内审核', type: 'success' });
      emits('submit');
    }
  });
};

// 点击给我留言
const clearTO = () => {
  state.form.pId = 0;
  state.form.toId = 0;
  state.form.toNickName = '';
  handleScrollToBottom();
};

defineExpose({
  clearTO
});

watch(
  () => props.articleId,
  n => {
    if (n) handleGetCommentFn();
  },
  { immediate: true }
);
</script>

<style lang="scss" scoped>
.comment-view-container {
  margin-top: 20px;
  width: 100%;
  .max-width-center {
    padding: 15px;
    background-color: var(--bg-warp-color);
    border-radius: var(--border-radius-2);
    height: 100%;
    max-width: var(--content-max-width);
    margin: 0 auto;
    .comment-view-content {
      background-color: var(--bg-content-color);
      border: 1px solid var(--border-color);
      border-radius: var(--border-radius-2);
      overflow: hidden;
      .comment-item {
        background-color: var(--bg-warp-light-color-2);
        padding: 15px;
        padding-bottom: 30px;
        border-bottom: 1px solid var(--border-color);
        &:last-child {
          margin-bottom: 0;
          border-bottom-left-radius: var(--border-radius-2);
          border-bottom-right-radius: var(--border-radius-2);
        }
        &:first-child {
          border-top-left-radius: var(--border-radius-2);
          border-top-right-radius: var(--border-radius-2);
        }
        .info-warp {
          display: flex;
          padding: 10px 0;
          align-items: space-around;
          .avatar-warp {
            width: 30px;
            height: 30px;
            border-radius: 50%;
            overflow: hidden;
            img {
              width: 100%;
              height: 100%;
            }
          }
          .info {
            margin-left: 15px;
            display: flex;
            flex-direction: column;
            justify-content: space-around;
            font-size: 12px;
            .nick-name {
              display: flex;
              align-items: center;
              margin-bottom: 4px;

              .level {
                border: 1px solid #ddd;
                color: var(--text-color);
                font-family: 优设标题黑 !important;
              }
            }
          }
        }
        .content {
          text-indent: 30px;
          line-height: 20px;
          font-size: 14px;
        }
        .operation-warp {
          margin-top: 10px;
          padding: 10px 0 0 30px;
          display: flex;
          justify-content: flex-start;
          align-items: center;
          .like-warp {
            display: flex;
            align-items: center;
            .like-value {
              margin-left: 10px;
              display: inline-block;
              min-width: 30px;
            }
          }
          .comment-warp {
            margin-left: 10px;
            display: flex;
            align-items: center;
            .comment-icon {
              width: 19px;
            }
            .comment-value {
              margin-left: 10px;
            }
          }
        }
        .sub-comment {
          margin-top: 10px;
          padding-left: 30px;
          .sub-padding {
            background-color: var(--bg-content-color-2);
            border-radius: 5px;
            padding: 10px 10px;
            .sub-comment-item {
              margin: 5px 0;
              .title {
                font-size: 12px;
                line-height: 20px;
                padding-bottom: 10px;
                display: flex;
                align-items: center;
              }
              .sub-content {
                line-height: 20px;
                font-size: 14px;
                text-indent: 30px;
              }
            }
          }
        }
      }
    }
    .input-warp {
      margin-top: 20px;
      .input-title {
        font-size: 14px;
        line-height: 40px;
        display: flex;
        align-items: center;
      }
    }
  }
}
.m-comment-view-container {
  width: var(--content-max-width-m);
  margin: 0 auto;
}
.ttt {
  padding: 0 0.3125rem;
  height: 2.5rem;
  display: flex;
  justify-content: space-between;
  position: relative;
  .back-title {
    font-size: 0.875rem;
    line-height: 2.5rem;
    text-shadow: var(--text-shadow);
  }
  .back-me {
    position: absolute;
    top: 0;
    right: 0;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius-1);
    padding: 0 5px;
    height: 26px;
    line-height: 26px;
  }
}
.bozhu {
  padding: 0px 5px;
  font-size: 12px;
  border: 1px solid var(--theme-light-color-5);
  color: var(--theme-color);
  margin: 0 5px;
  border-radius: 5px;
  line-height: 20px;
}
</style>
